/**
 * 阿里云函数计算 - MP4 Faststart 优化
 * 
 * 触发方式：OSS 对象创建事件
 * 运行时：Node.js 16
 * 内存：2048 MB
 * 超时：600 秒（10分钟）
 */

const OSS = require('ali-oss');
const { exec } = require('child_process');
const fs = require('fs');
const path = require('path');

// OSS 配置（从环境变量读取）
const ossClient = new OSS({
  region: process.env.OSS_REGION,
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  bucket: process.env.OSS_BUCKET
});

exports.handler = async (event, context) => {
  const logger = context.logger;
  
  try {
    // 解析 OSS 事件
    const eventObj = JSON.parse(event.toString());
    const ossEvent = eventObj.events[0];
    
    const bucketName = ossEvent.oss.bucket.name;
    const objectKey = ossEvent.oss.object.key;
    
    logger.info(`开始处理文件: ${objectKey}`);
    
    // 只处理 MP4 文件，且不是已优化的文件
    if (!objectKey.endsWith('.mp4') || objectKey.includes('_faststart')) {
      logger.info('跳过非 MP4 文件或已优化文件');
      return 'skipped';
    }
    
    // 检查是否需要优化（通过 Object Meta 标记）
    const objectMeta = await ossClient.head(objectKey);
    if (objectMeta.meta && objectMeta.meta.faststart === 'true') {
      logger.info('文件已标记为 faststart，跳过');
      return 'already_optimized';
    }
    
    // 临时文件路径
    const inputPath = `/tmp/input_${Date.now()}.mp4`;
    const outputPath = `/tmp/output_${Date.now()}.mp4`;
    
    try {
      // 1. 下载文件
      logger.info('下载文件...');
      const result = await ossClient.get(objectKey);
      fs.writeFileSync(inputPath, result.content);
      
      const inputSize = fs.statSync(inputPath).size;
      logger.info(`文件大小: ${(inputSize / 1024 / 1024).toFixed(2)} MB`);
      
      // 2. 检查是否已经是 faststart 格式
      const isFaststart = await checkIfFaststart(inputPath, logger);
      if (isFaststart) {
        logger.info('文件已经是 faststart 格式，只添加标记');
        
        // 添加 meta 标记
        await ossClient.copy(objectKey, objectKey, {
          meta: {
            ...objectMeta.meta,
            faststart: 'true'
          }
        });
        
        return 'already_faststart';
      }
      
      // 3. FFmpeg 优化
      logger.info('开始 FFmpeg 优化...');
      await runFFmpeg(inputPath, outputPath, logger);
      
      const outputSize = fs.statSync(outputPath).size;
      logger.info(`优化后大小: ${(outputSize / 1024 / 1024).toFixed(2)} MB`);
      
      // 4. 上传回 OSS（覆盖原文件或创建新文件）
      logger.info('上传优化后的文件...');
      
      // 选项 A: 覆盖原文件
      await ossClient.put(objectKey, outputPath, {
        meta: {
          faststart: 'true',
          optimized_at: new Date().toISOString()
        }
      });
      
      // 选项 B: 创建新文件（如果需要保留原文件）
      // const newKey = objectKey.replace('.mp4', '_faststart.mp4');
      // await ossClient.put(newKey, outputPath, {
      //   meta: { faststart: 'true' }
      // });
      
      logger.info('处理完成');
      
      return {
        status: 'success',
        originalSize: inputSize,
        optimizedSize: outputSize,
        objectKey: objectKey
      };
      
    } finally {
      // 清理临时文件
      if (fs.existsSync(inputPath)) fs.unlinkSync(inputPath);
      if (fs.existsSync(outputPath)) fs.unlinkSync(outputPath);
    }
    
  } catch (error) {
    logger.error('处理失败:', error);
    throw error;
  }
};

// 检查文件是否已经是 faststart 格式
function checkIfFaststart(filePath, logger) {
  return new Promise((resolve) => {
    exec(`ffprobe -v error -show_entries format_tags=major_brand -of default=noprint_wrappers=1:nokey=1 "${filePath}"`,
      (error, stdout) => {
        if (error) {
          logger.warn('ffprobe 检查失败，假设需要优化');
          resolve(false);
          return;
        }
        
        // 简单检查：读取文件头部，看 moov 是否在 mdat 之前
        const buffer = Buffer.alloc(100);
        const fd = fs.openSync(filePath, 'r');
        fs.readSync(fd, buffer, 0, 100, 0);
        fs.closeSync(fd);
        
        // 查找 moov 和 mdat 的位置
        const moovPos = buffer.indexOf('moov');
        const mdatPos = buffer.indexOf('mdat');
        
        const isFaststart = moovPos !== -1 && moovPos < mdatPos;
        logger.info(`Faststart 检查: moov=${moovPos}, mdat=${mdatPos}, isFaststart=${isFaststart}`);
        
        resolve(isFaststart);
      }
    );
  });
}

// 运行 FFmpeg
function runFFmpeg(inputPath, outputPath, logger) {
  return new Promise((resolve, reject) => {
    const command = `ffmpeg -i "${inputPath}" -c copy -movflags +faststart "${outputPath}"`;
    
    logger.info(`执行命令: ${command}`);
    
    const startTime = Date.now();
    
    exec(command, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
      const duration = ((Date.now() - startTime) / 1000).toFixed(2);
      
      if (error) {
        logger.error(`FFmpeg 错误: ${error.message}`);
        logger.error(`stderr: ${stderr}`);
        reject(error);
        return;
      }
      
      logger.info(`FFmpeg 完成，耗时: ${duration}s`);
      resolve();
    });
  });
}
